package multi_thread.master.executors;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;

/**
 * @author Cheng Jun
 * Description: 具有切面功能的线程池，继承 ThreadPoolExecutor，并且重写三个切面方法 beforeExecute afterExecute terminated
 * @version 1.0
 * @date 2022/5/21 17:00
 */
public class AOPThreadPoolExecutor extends ThreadPoolExecutor {

    public AOPThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue) {
        super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue);
    }

    public AOPThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory) {
        super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory);
    }

    public AOPThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, RejectedExecutionHandler handler) {
        super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, handler);
    }

    public AOPThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler) {
        super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory, handler);
    }

    public static void main(String[] args) {
        // 创建自定义的切面线程池，并用到了自定义的线程工厂类，拒绝策略为直接抛弃
        AOPThreadPoolExecutor aopThreadPoolExecutor = new AOPThreadPoolExecutor(2, 4, 60L, TimeUnit.SECONDS,
                new ArrayBlockingQueue<>(256),
                new Executor_CustomedThreadPool.MyThreadFactory("切面线程池"),
                new AbortPolicy()
        );
        System.out.println("所有的核心线程已经初始化完成：完成数 " + aopThreadPoolExecutor.prestartAllCoreThreads());
        List<Future<Integer>> taskList = new ArrayList<>(256);
        for (int i = 0; i < 1; i++) {
            // Callable<Integer> callableTask = () -> {
            //     TimeUnit.SECONDS.sleep(2);
            //     // 演示 java.lang.ArithmeticException: / by zero
            //     int res = 10 / 0;
            //     int randomNum = ThreadLocalRandom.current().nextInt(10);
            //     System.out.println(Thread.currentThread().getName() + " 产生随机数：" + randomNum);
            //     return randomNum;
            // };
            // submit 提交的话，异常是绑定 FutureTask上，afterExecute 不能捕获到异常信息
            // taskList.add(aopThreadPoolExecutor.submit(callableTask));

            // 演示 execute 提交任务后，afterExecute 能捕获到异常信息
            Runnable task = () -> {
                try {
                    TimeUnit.SECONDS.sleep(2);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                // 演示 java.lang.ArithmeticException: / by zero
                int res = 10 / 0;
                int randomNum = ThreadLocalRandom.current().nextInt(10);
                System.out.println(Thread.currentThread().getName() + " 产生随机数：" + randomNum);
            };
            aopThreadPoolExecutor.execute(task);
        }
        for (Future<Integer> randomFuture : taskList) {
            try {
                // 使用 submit 提交的话，异常不能被 afterExecute 抛出，必须使用 get
                // 和 自定义线程工厂一样，自定义线程工厂的异常也不能被 Thread.UncaughtExceptionHandler 捕获
                System.out.println(randomFuture.get());
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (ExecutionException e) {
                e.printStackTrace();
            }
        }
        aopThreadPoolExecutor.shutdown();

    }

    @Override
    protected void beforeExecute(Thread t, Runnable r) {
        // 虽然父类的实现是一个空方法，但写上super.beforeExecute(t, r) 是良好的编程习惯
        super.beforeExecute(t, r);
        System.out.println(t.getName() + " 在" + LocalDateTime.now() + " 开始执行 " + r.toString());
    }

    @Override
    protected void afterExecute(Runnable r, Throwable t) {
        super.afterExecute(r, t);
        if (t != null) {
            System.out.println(r.toString() + " 在" + LocalDateTime.now() + " 执行过程出现异常：\n " + t.getMessage());
        } else {
            System.out.println(r.toString() + " 在" + LocalDateTime.now() + " 被执行完 ");
        }
    }

    @Override
    protected void terminated() {
        super.terminated();
        System.out.println("线程池终止前调用，此时线程池还没关闭。 " + this.isTerminated());
    }
}
